package dice.sinanya.dice.roll;

import dice.sinanya.dice.MakeNickToSender;
import dice.sinanya.entity.EntityTypeMessages;
import dice.sinanya.exceptions.DxSuccessException;
import dice.sinanya.exceptions.DxTimesException;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static dice.sinanya.system.MessagesTag.TAG_DX;
import static dice.sinanya.tools.getinfo.GetMessagesProperties.entitySystemProperties;
import static dice.sinanya.tools.getinfo.GetNickName.getNickName;
import static dice.sinanya.tools.makedata.RandomInt.random;
import static dice.sinanya.tools.makedata.Sender.sender;

public class Dx implements MakeNickToSender {
    private final Pattern getParam = Pattern.compile("(\\d+)*[a]*(\\d+)*[+]*(\\d+)*");
    private final EntityTypeMessages entityTypeMessages;

    public Dx(EntityTypeMessages entityTypeMessages) {
        this.entityTypeMessages = entityTypeMessages;
    }

    public void dx() throws DxTimesException, DxSuccessException {
        String tag = TAG_DX;
        String msg = entityTypeMessages.getMsgGet().getMsg().trim().replaceFirst(tag.substring(0, tag.length() - 2), "").trim();

        int time = 1;
        int success = 10;
        int add = 0;
        int resultNum;
        ArrayList<String> resultTmpStr;
        ArrayList<String> resultStr = new ArrayList<>();
        Matcher dxFind = getParam.matcher(msg);
        if (dxFind.find()) {
            time = getValue(dxFind.group(1), time);
            success = getValue(dxFind.group(2), success);
            if (dxFind.groupCount() == 3) {
                add = getValue(dxFind.group(3), add);
            }
        }
        if (success <= 1) {
            throw new DxSuccessException(entityTypeMessages);
        }

        if (time < 1 || time > 50) {
            throw new DxTimesException(entityTypeMessages);
        }
        ArrayList<ArrayList<Integer>> resultList = new ArrayList<>();
        do {
            ArrayList<Integer> tmp = makeFunction(time);
            resultList.add(tmp);
            time = getSuccessNum(tmp, success);
        } while (time != 0);

        int criticalNum = 0;
        for (ArrayList<Integer> tmp : resultList.subList(0, Math.max(resultList.size() - 2, resultList.size() - 1))) {
            if (getCritical(tmp, success)) {
                criticalNum++;
            }
        }
        int max = getMax(resultList.get(resultList.size() - 1));
        boolean findMax = false;
        resultNum = criticalNum * 10 + max;
        for (int i = 0; i < resultList.size(); i++) {
            resultTmpStr = new ArrayList<>();
            for (Integer tmp2 : resultList.get(i)) {
                if (i == resultList.size() - 1) {
                    if (tmp2 == max && !findMax) {
                        resultTmpStr.add(String.format("[%d]", tmp2));
                        findMax = true;
                    } else {
                        resultTmpStr.add(String.valueOf(tmp2));
                    }
                    continue;
                }
                if (tmp2 >= success) {
                    resultTmpStr.add(String.format("<%d>", tmp2));
                } else {
                    resultTmpStr.add(String.valueOf(tmp2));
                }
            }
            resultStr.add(String.format("{%s}", StringUtils.join(resultTmpStr, ",")));
        }
        String senderStr;
        if (add != 0) {
            senderStr = StringUtils.join(resultStr, "\n+") + "\n+" + add + "\n=" + (resultNum + add);
        } else {
            senderStr = StringUtils.join(resultStr, "\n+") + "\n=" + resultNum;
        }
        sender(entityTypeMessages, String.format("%s因为%s%s%s", makeNickToSender(getNickName(entityTypeMessages)), msg, entitySystemProperties.getRollInfo(entityTypeMessages.getFromGroupString()), senderStr));
    }

    private boolean getCritical(ArrayList<Integer> input, int success) {
        for (Integer tmp : input) {
            if (tmp >= success) {
                return true;
            }
        }
        return false;
    }

    private int getMax(ArrayList<Integer> input) {
        int result = 0;
        for (Integer tmp : input) {
            if (tmp > result) {
                result = tmp;
            }
        }
        return result;
    }

    private int getSuccessNum(ArrayList<Integer> input, int success) {
        int result = 0;
        for (Integer tmp : input) {
            if (tmp >= success) {
                result++;
            }
        }
        return result;
    }

    private ArrayList<Integer> makeFunction(int times) {
        ArrayList<Integer> resultList = new ArrayList<>();
        for (int i = 0; i < times; i++) {
            resultList.add(random(1, 10));
        }
        return resultList;
    }

    private int getValue(String input, int defaultValue) {
        if (input != null) {
            return Integer.parseInt(input);
        } else {
            return defaultValue;
        }
    }
}